#ifndef     __UART_H
#define     __UART_H

#include "./dma.h"
#include "./rcc.h"

namespace device::uart {

namespace CR1 {

/**
 * @brief 
 * 0: USART分频器和输出被禁止
 * 1: USART模块使能
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> UE = 0;

template <>
inline constexpr uint32_t UE<1> = 0x01 << 13;

/**
 * @brief 
 * 0: 1个起始位, 8个数据位, n个停止位
 * 1: 1个起始位, 9个数据位, n个停止位
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> M = 0;

template <>
inline constexpr uint32_t M<1> = 0x01 << 12;

/**
 * @brief 
 * 0: 被空闲总线唤醒
 * 1: 被地址标记唤醒
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> WAKE = 0;

template <>
inline constexpr uint32_t WAKE<1> = 0x01 << 11;

/**
 * @brief 
 * 0: 禁止奇偶校验
 * 1: 使能奇偶校验
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> PCE = 0;

template <>
inline constexpr uint32_t PCE<1> = 0x01 << 10;

/**
 * @brief 
 * 0: 偶校验
 * 1: 奇校验
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> PS = 0;

template <>
inline constexpr uint32_t PS<1> = 0x01 << 9;

/**
 * @brief 奇偶校验出错
 * 0: 禁止产生中断
 * 1: 允许产生中断
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> PEIE = 0;

template <>
inline constexpr uint32_t PEIE<1> = 0x01 << 8;

/**
 * @brief 发送缓冲区空
 * 0: 禁止产生中断
 * 1: 允许产生中断 
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> TXEIE = 0;

template <>
inline constexpr uint32_t TXEIE<1> = 0x01 << 7;

/**
 * @brief 发送完成
 * 0: 禁止产生中断
 * 1: 允许产生中断 
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> TCIE = 0;

template <>
inline constexpr uint32_t TCIE<1> = 0x01 << 6;

/**
 * @brief 接收缓冲区非空
 * 0: 禁止产生中断
 * 1: 允许产生中断 
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> RXNEIE = 0;

template <>
inline constexpr uint32_t RXNEIE<1> = 0x01 << 5;

/**
 * @brief 空闲中断
 * 0: 禁止产生中断
 * 1: 允许产生中断 
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> IDLEIE = 0;

template <>
inline constexpr uint32_t IDLEIE<1> = 0x01 << 4;

/**
 * @brief 
 * 0: 禁止发送
 * 1: 允许发送
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> TE = 0;

template <>
inline constexpr uint32_t TE<1> = 0x01 << 3;

/**
 * @brief 
 * 0: 禁止接收
 * 1: 允许接收
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> RE = 0;

template <>
inline constexpr uint32_t RE<1> = 0x01 << 2;

/**
 * @brief 
 * 0: 接收器处于正常工作模式
 * 1: 接收器处于静默模式
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> RWU = 0;

template <>
inline constexpr uint32_t RWU<1> = 0x01 << 1;

/**
 * @brief 
 * 0: 没有发送断开字符
 * 1: 将要发送断开字符
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> SBK = 0;

template <>
inline constexpr uint32_t SBK<1> = 0x01;


}

namespace CR2 {

/**
 * @brief 
 * 0: 禁止LIN模式
 * 1: 使能LIN模式
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> LINEN = 0;

template <>
inline constexpr uint32_t LINEN<1> = 0x01 << 14;

/**
 * @brief 
 * 0: 1个停止位
 * 1: 0.5个停止位
 * 2: 2个停止位
 * 3: 1.5个停止位
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 4), uint32_t> STOP = 0;

template <>
inline constexpr uint32_t STOP<1> = 0x01 << 12;

template <>
inline constexpr uint32_t STOP<2> = 0x02 << 12;

template <>
inline constexpr uint32_t STOP<3> = 0x03 << 12;

/**
 * @brief 
 * 0: 禁止CK引脚
 * 1: 使能CK引脚
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> CLKEN = 0;

template <>
inline constexpr uint32_t CLKEN<1> = 0x01 << 11;

/**
 * @brief 
 * 0: 总线空闲时CK引脚保持低电平
 * 1: 总线空闲时CK引脚保持高电平
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> CPOL = 0;

template <>
inline constexpr uint32_t CPOL<1> = 0x01 << 10;

/**
 * @brief 
 * 0: 在时钟的第一个边沿进行数据捕获
 * 1: 在时钟的第二个边沿进行数据捕获
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> CPHA = 0;

template <>
inline constexpr uint32_t CPHA<1> = 0x01 << 9;

/**
 * @brief 
 * 0: 最后一位数据的时钟脉冲不从CK输出
 * 1: 最后一位数据的时钟脉冲会从CK输出
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> LBCL = 0;

template <>
inline constexpr uint32_t LBCL<1> = 0x01 << 8;

/**
 * @brief 
 * 0: LIN断开符检测中断禁止
 * 1: LIN断开符检测中断使能
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> LBDIE = 0;

template <>
inline constexpr uint32_t LBDIE<1> = 0x01 << 6;

/**
 * @brief 
 * 0: 10位的断开符检测
 * 1: 11位的断开符检测
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> LBDL = 0;

template <>
inline constexpr uint32_t LBDL<1> = 0x01 << 5;

/**
 * @brief 
 * 本设备USART节点地址
 */
template <uint8_t x>
inline constexpr std::enable_if_t<(x < 16), uint32_t> ADD = x;

}

namespace CR3 {

/**
 * @brief 
 * 0: 禁止CTS中断
 * 1: 允许CTS中断
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> CTSIE = 0;

template <>
inline constexpr uint32_t CTSIE<1> = 0x01 << 10;

/**
 * @brief 
 * 0: 禁止CTS硬件流控制
 * 1: 允许CTS硬件流控制
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> CTSE = 0;

template <>
inline constexpr uint32_t CTSE<1> = 0x01 << 9;

/**
 * @brief 
 * 0: 禁止RTS硬件流控制
 * 1: 允许RTS硬件流控制
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> RTSE = 0;

template <>
inline constexpr uint32_t RTSE<1> = 0x01 << 8;

/**
 * @brief 
 * 0: 禁止DMA发送
 * 1: 允许DMA发送
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> DMAT = 0;

template <>
inline constexpr uint32_t DMAT<1> = 0x01 << 7;

/**
 * @brief 
 * 0: 禁止DMA接收
 * 1: 允许DMA接收
 */
template <uint8_t v>
inline constexpr std::enable_if_t<(v < 2), uint32_t> DMAR = 0;

template <>
inline constexpr uint32_t DMAR<1> = 0x01 << 6;

}

template <uint32_t Base>
struct Uart {

public:
    static constexpr uint32_t Freq = rcc::PeriphFreq<Base>;
    using TxChan = dma::UartTxChan<Base>;
    using RxChan = dma::UartRxChan<Base>;

private:
    template <uint32_t flag>
    static inline bool IsFlag() {
        return (reinterpret_cast<USART_TypeDef *>(Base)->SR & flag) != 0;
    }

public:
    static inline void WriteByDma(const void *buf, uint32_t len) {
        TxChan::WriteForUart(buf, len,  
            reinterpret_cast<uint32_t>(&(reinterpret_cast<USART_TypeDef *>(Base)->DR))
        );
    }

    static inline void RecvByDma(void *buf, uint32_t len) {
        RxChan::RecvForUart(buf, len,
            reinterpret_cast<uint32_t>(&(reinterpret_cast<USART_TypeDef *>(Base)->DR))
        );
    }

    static inline void InitWithDefault(uint32_t baud_rate) {
        reinterpret_cast<USART_TypeDef *>(Base)->CR1 = 0;
        reinterpret_cast<USART_TypeDef *>(Base)->CR2 = 0;
        reinterpret_cast<USART_TypeDef *>(Base)->CR3 = CR3::DMAT<1> + CR3::DMAR<1>;
        reinterpret_cast<USART_TypeDef *>(Base)->BRR = Freq / baud_rate;
        reinterpret_cast<USART_TypeDef *>(Base)->CR1 = 
            CR1::UE<1> +
            CR1::M<0> +
            CR1::WAKE<0> +
            CR1::PCE<0> +
            CR1::PS<0> +
            CR1::PEIE<0> +
            CR1::TXEIE<0> +
            CR1::TCIE<0> +
            CR1::RXNEIE<0> +
            CR1::IDLEIE<1> +
            CR1::TE<1> +
            CR1::RE<1> +
            CR1::RWU<0> +
            CR1::SBK<0>;
    }

    static inline bool IsCTS() {
        return IsFlag<USART_SR_CTS>();
    }

    static inline bool IsLBD() {
        return IsFlag<USART_SR_LBD>();
    }

    static inline bool IsTXE() {
        return IsFlag<USART_SR_TXE>();
    }

    static inline bool IsTC() {
        return IsFlag<USART_SR_TC>();
    }

    static inline bool IsRXNE() {
        return IsFlag<USART_SR_RXNE>();
    }

    static inline bool IsIDLE() {
        return IsFlag<USART_SR_IDLE>();
    }

    static inline void ClrIDLE() {
        uint32_t clr = reinterpret_cast<USART_TypeDef *>(Base)->DR;
    }

    static inline bool IsORE() {
        return IsFlag<USART_SR_ORE>();
    }

    static inline bool IsNE() {
        return IsFlag<USART_SR_NE>();
    }

    static inline bool IsFE() {
        return IsFlag<USART_SR_FE>();
    }

    static inline bool IsPE() {
        return IsFlag<USART_SR_PE>();
    }

};

}


#endif
